﻿Imports System.Net.Sockets
Imports System.Text

Public Class Response
    Public Const SERVER_NAME As String = "Mobimint 0.1 beta"

    Dim NS As NetworkStream
    Dim GzipStream As IO.Compression.GZipStream

    Dim ClientSocket As Socket
    Dim BeforeWrite As Boolean = True
    Dim StatusSent As Boolean = False
    
    Private _Gzip As Boolean = False
    Public Property Gzip() As Boolean
        Get
            Return _Gzip
        End Get
        Set(ByVal value As Boolean)
            _Gzip = value
            If value Then
                GzipStream = New IO.Compression.GZipStream(NS, IO.Compression.CompressionMode.Compress)
            End If
        End Set
    End Property


    Public Sub New(ByRef ClientSocket As Socket)
        Me.ClientSocket = ClientSocket
        NS = New NetworkStream(ClientSocket, IO.FileAccess.Write)
    End Sub

    Public Sub CommonHeaders(ByVal ContentLength As Long, ByVal ContentType As String)
        Me.Gzip = Me.IsGzipped(ContentLength, ContentType)
        Me.SendStatusResponse(eStatusCode.STATUS200_OK)
        'Me.AppendHeader(eHttpHeader.Accept_Ranges, "bytes")

        If Not Me.Gzip Then Me.AppendHeader(eHttpHeader.Content_Length, ContentLength.ToString)

        'Me.AppendHeader(eHttpHeader.Expires, (New Date(Now.Year + 1, 1, 1)).ToHttpDateFormat)
        'Me.AppendHeader(eHttpHeader.Last_Modified, (New Date(Now.Year - 1, 1, 1)).ToHttpDateFormat)
        Me.AppendHeader(eHttpHeader.Cache_Control, "max-age=864000")
        Me.AppendHeader(eHttpHeader.Content_Type, ContentType)
        Me.AppendHeader(eHttpHeader.Server, SERVER_NAME)
        Me.AppendHeader(eHttpHeader.Cache_Control, "public")
        If Gzip Then Me.AppendHeader(eHttpHeader.Content_Encoding, "gzip")
    End Sub

    Public Sub SendStatusResponse(ByVal StatusCode As eStatusCode)
        If Not StatusSent Then
            Dim HttpHeader As String = String.Format("HTTP/1.1 {0}{1}", StatusCode.ToString.Replace("STATUS", "").Replace("_", " "), vbCrLf)
            WriteHeader(HttpHeader)
            StatusSent = True
        Else
            Throw New Exception("Status Code already sent.")
        End If
    End Sub

    Public Sub AppendHeader(ByVal HttpHeader As eHttpHeader, ByVal Value As String)
        If Not StatusSent Then Throw New Exception("Status Code should be send before appending header")
        If Not BeforeWrite Then Throw New Exception("Cannot append the response header after sending data")

        Dim HeaderString As String
        HeaderString = String.Format("{0}: {1}{2}", HttpHeader.ToString.Replace("_", "-"), Value, vbCrLf)
        WriteHeader(HeaderString)
    End Sub

    Public Sub Write(ByVal Binary() As Byte)
        If BeforeWrite Then
            ClientSocket.Send(Encoding.ASCII.GetBytes(vbCrLf), Encoding.ASCII.GetBytes(vbCrLf).Length, 0)
        End If
        'ClientSocket.Send(Binary, Binary.Length, 0)
        
        If Gzip Then
            GzipStream.Write(Binary, 0, Binary.Length)
        Else
            NS.Write(Binary, 0, Binary.Length)
        End If

        BeforeWrite = False
    End Sub

    Public Sub Write(ByVal Text As String)
        Write(Encoding.ASCII.GetBytes(Text))
    End Sub

    Public Sub WriteJson(ByVal Json As String)
        Me.SendStatusResponse(eStatusCode.STATUS200_OK)
        'Me.AppendHeader(eHttpHeader.Accept_Ranges, "bytes")
        'Me.AppendHeader(eHttpHeader.Content_Length, Json.Length)
        If GZip Then Me.AppendHeader(eHttpHeader.Content_Encoding, "gzip")
        Me.AppendHeader(eHttpHeader.Content_Type, "application/json")
        Me.AppendHeader(eHttpHeader.Server, "Mobimin 1.0")
        Me.Write(Json)
        Me.Close()
    End Sub

    Private Sub WriteHeader(ByVal Header As String)
        Dim Binary() As Byte
        Binary = Encoding.ASCII.GetBytes(Header)
        ClientSocket.Send(Binary, Binary.Length, 0)
    End Sub

    Public Sub Close()
        If Gzip Then
            GzipStream.Close()
        End If

        NS.Close()
        ClientSocket.Close()
        GC.Collect()
    End Sub

    Private Function IsGzipped(ByVal ContentLength As Long, ByVal MimeType As String) As Boolean
        If ContentLength < 1024 Then
            Return False
        End If
        Dim GZippedMime = (New String() {"text/html", "application/javascript", "text/css"}).ToList
        If GZippedMime.Contains(MimeType) Then
            Return True
        End If
        Return False
    End Function
End Class
